﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using SqlRunner.uiStatus;
using SQLRunnerLib;
using SQLRunnerLib.Services;
using System.Text.RegularExpressions;
using SQLRunnerLib.Util;
using SQLServices.Log;
using SQLRunnerLib.Project;
using System.IO;
using System.Linq;

namespace SqlRunner
{
    // TODO: Binding of the form helps in a lot of way but means that the cancel button does not work. I need to clone the environment.
    public partial class frmEnvironmentDetails : Form
    {
        private SQLEnvironment _environment;
        private SQLProject _sqlProject;

        public frmEnvironmentDetails()
        {
            InitializeComponent();
            SetGroups();          
        }

        public frmEnvironmentDetails(SQLEnvironment environment, SQLProject sqlProject)
            : this()
        {
            _environment = environment;
            _sqlProject = sqlProject;

            cboAuthentication.DataSource = Enum.GetNames(typeof(AuthenticationType));

            environmentBindingSource.DataSource = _environment;
//            placeHoldersBindingSource.DataSource = environment.PlaceHolders;
            CheckFormStatus();
        }

        #region Event Handlers
        private void cboAuthentication_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboAuthentication.Text != string.Empty)
            {
                if ((AuthenticationType)Enum.Parse(typeof(AuthenticationType), cboAuthentication.Text) == AuthenticationType.WindowsAuthentication)
                {
                    txtUsername.Text = string.Empty;
                    txtPassword.Text = string.Empty;
                    txtUsername.Enabled = false;
                    txtPassword.Enabled = false;
                    chkRemeberPassword.Enabled = false;
                    chkRemeberPassword.Checked = false;
                }
                else
                {
                    txtUsername.Enabled = true;
                    txtPassword.Enabled = true;
                    chkRemeberPassword.Enabled = true;
                }
            }
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            ensureEnvironmentNameUnique();

            _environment.Validate();
            
            try
            {
                testConnectionSettings();
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Connection failed: {0}", ex.Message));
            }
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            try
            {
                Cursor = Cursors.WaitCursor;
                List<string> servers = ServiceContainer.Instance.SQLServerFinder.GetSQLServers();
                if (servers == null)
                {
                    MessageBox.Show("No SQL Servers were found.");
                }
                else
                {
                    frmServerSearch searchForm = new frmServerSearch(servers);
                    DialogResult result = searchForm.ShowDialog(this);
                    if (result == DialogResult.OK)
                    {
                        if (!cboServer.Items.Contains(searchForm.Server))
                        {
                            cboServer.Items.Add(searchForm.Server);
                        }
                        if (cboServer.Text.Equals(searchForm.Server)) return;
                        cboServer.Text = searchForm.Server;
                        CheckFormStatus();
                    }
                }
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }
        
        private void cboDatabase_DropDown(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            setComment("Connecting to [{0}] SQL Server, please wait ...", cboServer.Text);
            try
            {
                PopulateDatabaseDropdown();
                if (!string.IsNullOrEmpty(_environment.DatabaseName))
                {
                    cboDatabase.SelectedItem = _environment.DatabaseName;
                }
                setComment("Connection was established to server [{0}], please select database.", cboServer.Text);
            }
            catch (Exception ex)
            {
                Regex expression = new Regex(@"(\[(\w*\s*)*\])+");
                string msg = expression.Replace(ex.Message, "");
                ServiceContainer.Instance.Logger.LogMessage(String.Format("Error openning connection: {0}", msg), MsgLevel.Error);
                MessageBox.Show(this, String.Format(
                    "The following error took place when connecting to the [{0}] SQL Server: \n\n{1}"
                    , cboServer.Text, msg), "SQL Runner - Error openning connection");
                setComment("Idle, please connect to SQL Server", "");
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
            CheckFormStatus();
        }

        private void btnTestConnection_Click(object sender, EventArgs e)
        {
            try
            {
                testConnectionSettings();
                MessageBox.Show("Connection successful.");
            }
            catch (Exception ex)
            {
                MessageBox.Show(string.Format("Connection failed: {0}", ex.Message));
            }
        }
        #endregion

        private void FindAndPopulatePlaceHolders()
        {
            Regex rx = new Regex(@"\${(?<placeHolder>\w*)}");
            foreach (FileInfo file in _sqlProject.FilesInProject())
            {
                using (StreamReader aStream = new StreamReader(file.OpenRead()))
                {
                    string strSQL = aStream.ReadToEnd();
                    aStream.Close();

                    MatchCollection col = rx.Matches(strSQL);

                    foreach (Match placeHolderMatch in col)
                    {
                        string placeHolderName = placeHolderMatch.Groups["placeHolder"].Value;
                        PlaceHolder placeHolder = _environment.PlaceHolders.Where(p => p.Name == placeHolderName).FirstOrDefault();
                        if (placeHolder == null)
                        {
                            placeHolder = new PlaceHolder(placeHolderName, string.Empty);
                            _environment.PlaceHolders.Add(placeHolder);
                        }
                    }
                }
            }

            placeHoldersBindingSource.DataSource = _environment.PlaceHolders;
        }

        private void testConnectionSettings()
        {
            ServiceContainer.Instance.Logger.LogMessage("Testing connection settings are valid.");
                _environment.Validate();
                _environment.TestConnection();
        }

        private void ensureEnvironmentNameUnique()
        {
            foreach (SQLEnvironment env in _sqlProject.Environments)
            {
                if (env != _environment && env.Name == txtEnvironment.Text)
                {
                    MessageBox.Show(string.Format("There is already an environment with the name [{0}]", txtEnvironment.Text));
                    DialogResult = DialogResult.None;
                }
            }
        }

        private void PopulateDatabaseDropdown()
        {
            _environment.ConnectToServer();
            cboDatabase.Items.Clear();
            cboDatabase.Items.AddRange(ServiceContainer.Instance.SQLConnection.ListOfDatabases().ToArray());

            // Disconnect as there is no reason to keep the connection open longer than needed.
            _environment.Disconnect();
        }

        private void setComment(string format, params object[] args)
        {
            ServiceContainer.Instance.Logger.LogMessage("setComment method was called");
            toolStripStatus.Text = String.Format(format, args);
        }

        private void btnDiscoverPlaceHolders_Click(object sender, EventArgs e)
        {
            try
            {
                this.Cursor = Cursors.WaitCursor;
                FindAndPopulatePlaceHolders();
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

    }
}
